//
//  NSObject+ZBProperty.m
//  02-runtime获取类的信息
//
//  Created by apple on 2018/6/6.
//  Copyright © 2018年 apple. All rights reserved.
//

#import "NSObject+ZBProperty.h"
#import <objc/runtime.h>

@implementation NSObject (ZBProperty)
+ (NSArray *)zb_getPropertyList
{
    Class kTargetClass = self;
    NSMutableArray *propsNameArray = [NSMutableArray array];
    while (kTargetClass != [NSObject class])
    {
        unsigned count;
        objc_property_t *props = class_copyPropertyList(kTargetClass, &count);
        for (unsigned i = 0; i< count; i++)
        {
            // objc_property_t 属性类型
            objc_property_t property = props[i];
            
            // 获取属性的名称 C语言字符串
            const char *propertyName =property_getName(property);
            //char 转化为NSstring
            NSString *name = [NSString stringWithUTF8String:propertyName];
            
            [propsNameArray addObject:name];
        }
        //C语言的东东，记得释放
        free(props);
        //类似递归的思想
        kTargetClass = [kTargetClass superclass];
    }
    return propsNameArray;
}

+ (NSString *)zb_getPropertyTypeWithPropertyName:(NSString *)name
{
    if(name.length ==0){
        return nil;
    }
    const char * property_Name = name.UTF8String;
    NSString *property_data_type = nil;
    Class kTargetClass = self;
    
    
    NSArray *protertyList = [self zb_getPropertyList];
    if(![protertyList containsObject:name]){
        return property_data_type;
    }
    unsigned count;
    objc_property_t *props = class_copyPropertyList(kTargetClass, &count);
    
    for (unsigned i = 0; i < count; i++) {
        // objc_property_t 属性类型
        objc_property_t property = props[i];
        
        // 获取属性的名称 C语言字符串
        const char *propertyName =property_getName(property);
        
        if(strcmp(propertyName, property_Name) == 0){
            const char *property_Arribute = property_getAttributes(property);
            
            //char 转化为NSstring
            NSString *propertyArribute = [NSString stringWithUTF8String:property_Arribute];
            
            NSUInteger dotLoc = [propertyArribute rangeOfString:@","].location;
            
            NSString *code = nil;
            NSUInteger loc = 1;
            if (dotLoc == NSNotFound) { // 没有,
                code = [propertyArribute substringFromIndex:loc];
            } else {
                code = [propertyArribute substringWithRange:NSMakeRange(loc, dotLoc - loc)];
            }
            NSString *type = [self handlePropertyCode:code];
            property_data_type = type;
            break;
        }
    }
    //C语言的东东，记得释放
    free(props);
    
    return property_data_type;
    
}

- (NSString *)zb_getPropertyTypeWithPropertyName:(NSString *)name
{
    return [[self class] zb_getPropertyTypeWithPropertyName:name];
}

#pragma mark - pravate
+ (NSString *)handlePropertyCode:(NSString *)code
{
    NSString *type = nil;
    
    if(code.length == 0){
        return ZBPropertyTypeUnknow;
    }
    if([code isEqualToString:ZBPropertyTypeRuntimeId]){
        return ZBPropertyTypeId;
    }else if ([code isEqualToString:ZBPropertyTypeRuntimeSEL]){
        return ZBPropertyTypeSEL;
    }else if ([code isEqualToString:ZBPropertyTypeRuntimeClass]){
        return ZBPropertyTypeClass;
    }else if ([code isEqualToString:ZBPropertyTypeRuntimeBlock]){
        return ZBPropertyTypeBlock;
    }else if ([code isEqualToString:ZBPropertyTypeRuntimePointer]){
        return ZBPropertyTypeChar;
    }else if ([code isEqualToString:ZBPropertyTypeRuntimeIvar] ||
              [code isEqualToString:ZBPropertyTypeRuntimeMethod]) {
        return nil;
        
    }else if (code.length > 3 && [code hasPrefix:@"@\""])
    {
        // 去掉@"和"，截取中间的类型名称
        code = [code substringWithRange:NSMakeRange(2, code.length - 3)];
        type = code;
        return type;
    }
    
    // 是否为数字类型
    NSString *lowerCode = code.lowercaseString;
    NSArray *numberTypes = @[ZBPropertyTypeRuntimeInt, ZBPropertyTypeRuntimeShort, ZBPropertyTypeRuntimeBOOL1, ZBPropertyTypeRuntimeBOOL2, ZBPropertyTypeRuntimeFloat, ZBPropertyTypeRuntimeDouble, ZBPropertyTypeRuntimeLong, ZBPropertyTypeRuntimeLongLong];
    if ([numberTypes containsObject:lowerCode]) {
        type = ZBPropertyTypeConstant;
    }else{
        type = ZBPropertyTypeUnknow;
    }
    return type;
}
/**
 *  成员变量类型（属性类型）
 */
NSString *const ZBPropertyTypeRuntimeInt = @"i";
NSString *const ZBPropertyTypeRuntimeShort = @"s";
NSString *const ZBPropertyTypeRuntimeFloat = @"f";
NSString *const ZBPropertyTypeRuntimeDouble = @"d";
NSString *const ZBPropertyTypeRuntimeLong = @"l";
NSString *const ZBPropertyTypeRuntimeLongLong = @"q";
NSString *const ZBPropertyTypeRuntimeChar = @"c";
NSString *const ZBPropertyTypeRuntimeBOOL1 = @"c";
NSString *const ZBPropertyTypeRuntimeBOOL2 = @"b";
NSString *const ZBPropertyTypeRuntimePointer = @"*";

NSString *const ZBPropertyTypeRuntimeIvar = @"^{objc_ivar=}";
NSString *const ZBPropertyTypeRuntimeMethod = @"^{objc_method=}";
NSString *const ZBPropertyTypeRuntimeBlock = @"@?";
NSString *const ZBPropertyTypeRuntimeClass = @"#";
NSString *const ZBPropertyTypeRuntimeSEL = @":";
NSString *const ZBPropertyTypeRuntimeId = @"@";


//自定义属性类型 - 常量类型的总称
NSString *const ZBPropertyTypeConstant = @"ZBConstant";
//id类型
NSString *const ZBPropertyTypeId = @"id";
//自定义属性类型 - SEL类型
NSString *const ZBPropertyTypeSEL = @"SEL";
//自定义属性类型 - Block类型
NSString *const ZBPropertyTypeBlock = @"Block";
//自定义属性类型 - Class类型
NSString *const ZBPropertyTypeClass = @"Class";
//自定义属性类型 - Char类型
NSString *const ZBPropertyTypeChar = @"Char";
//自定义属性类型 - 不识别类型
NSString *const ZBPropertyTypeUnknow = @"Unknow";
@end
